package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CodeMsg;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.PayFeignApi;
import cn.wolfcode.feign.PayIntergralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by wolfcode-lanxw
 */
@Service
@GlobalTransactional
@Slf4j
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public String doseckill(Integer time, Long seckillId, Long phone) {

        //1 减少库存

        int count = seckillProductMapper.decrStock(seckillId);
        if (count == 0) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //2 创建订单保存到数据库
        SeckillProductVo vo = seckillProductService.find(time, seckillId);
        OrderInfo orderInfo = new OrderInfo();
        IdGenerateUtil idGenerateUtil = IdGenerateUtil.get();

        orderInfo.setOrderNo(idGenerateUtil.nextId() + "");
        orderInfo.setCreateDate(new Date());
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setProductCount(vo.getStockCount());
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setSeckillId(seckillId);
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setSeckillTime(vo.getTime());
        orderInfo.setUserId(phone);
        orderInfo.setIntergral(vo.getIntergral());
        orderInfoMapper.insert(orderInfo);
        //3 在redis当中存入数据为了重复下单做铺垫,下单就存进redis下次查出来就不能下单了
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time + ""), phone + ":" + seckillId);
        return orderInfo.getOrderNo();
    }

    @Override
    public void orderTimeout(OrderMQResult orderMQResult) {
        //1.判断订单是否支付
        OrderInfo orderInfo = orderInfoMapper.find(orderMQResult.getOrderNo());
        //2.如果是未支付状态
        if (OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())) {
            //3.回补真实库存
            seckillProductMapper.decrStock(orderMQResult.getSeckillId());
            //4.回补预库存
            seckillProductService.syncRedisStockCount(orderMQResult.getSeckillId(), orderMQResult.getTime());
            //5.修改本地标识
            rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, orderMQResult.getSeckillId());
            //6.修改订单状态为超时未支付状态
            int count = orderInfoMapper.updateCancelStatus(orderMQResult.getOrderNo(), OrderInfo.STATUS_TIMEOUT);
            if (count == 0) {
                throw new BusinessException(SeckillCodeMsg.CANCEL_ORDER_ERROR);
            }
            log.info("超时取消业务完成");
        }

    }

    @Override
    public OrderInfo find(String orderNo) {
        Object object = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        if (StringUtils.isEmpty(object + "")) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_ERROR);
        }
        return JSON.parseObject(object + "", OrderInfo.class);
    }

    @Autowired
    private PayFeignApi payFeignApi;
    @Value("${pay.returnUrl}")
    private String returlUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;

    @Override
    public String payOnline(String orderNO) {
        OrderInfo orderInfo = find(orderNO);
        PayVo payVo = new PayVo();
        payVo.setBody(orderInfo.getProductName());
        payVo.setOutTradeNo(orderNO);
        payVo.setSubject(orderInfo.getProductName());
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + "");
        //调用支付服务返回一个
        payVo.setNotifyUrl(notifyUrl);
        payVo.setReturnUrl(returlUrl);
        Result<String> pay = payFeignApi.pay(payVo);
        return pay.getData();
    }

    @Override
    public void paySuccess(String orderNo) {
        //插入一条流水号
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        PayLog payLog=new PayLog();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTradeNo(orderNo);
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payLogMapper.insert(payLog);
        //修改订单状态
        int count = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_ONLINE);
        //如果修改失败进行退款
        if(count==0){
            refundOnline(orderInfo);
        }
    }

    @Override
    public void refundOnline(OrderInfo orderInfo) {
        //加一条退款流水
        RefundLog refundLog=new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundType(orderInfo.getPayType());
        refundLog.setRefundReason("不想要了");
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);
        //远程调用支付服务进行退款
        RefundVo refundVo=new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo());
        refundVo.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundVo.setRefundReason("不想要了");
        Result<Boolean> result=payFeignApi.refundOnline(refundVo);
        if(!result.getData()){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //把订单修改成已退款状态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if(count==0){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillId(),orderInfo.getSeckillTime());
        //修改本地标识
        rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }
    @Autowired
    private PayIntergralFeignApi payIntergralFeignApi;
    @Override
    @GlobalTransactional
    public void payIntergral(String orderNo) {
        //插入一条流水
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        PayLog payLog=new PayLog();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTradeNo(orderNo);
        payLog.setPayType(OrderInfo.PAYTYPE_INTERGRAL);
        payLog.setTotalAmount(orderInfo.getSeckillPrice()+"");
        payLogMapper.insert(payLog);
        //调用积分支付服务
        OperateIntergralVo operateIntergralVo=new OperateIntergralVo();
        operateIntergralVo.setInfo("没有买卖就没有伤害");
        operateIntergralVo.setPk(orderNo);
        operateIntergralVo.setUserId(orderInfo.getUserId());
        operateIntergralVo.setValue(orderInfo.getIntergral());
        Result<String> result = payIntergralFeignApi.decrIntergral(operateIntergralVo);
        if(result==null||result.hasError()){
            if(result.getCode()==500602){
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_NOT_ENOUGH);
            }else {
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_ERROR);
            }
        }
        int i=1/0;
        //修改订单状态
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_INTERGRAL);
    }

    @Override
    public void refundIntergral(OrderInfo orderInfo) {
        //加一条退款流水
        RefundLog refundLog=new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundType(orderInfo.getPayType());
        refundLog.setRefundReason("不想要了");
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);
        //调用积分服务进行积分增加
        OperateIntergralVo operateIntergralVo=new OperateIntergralVo();
        operateIntergralVo.setInfo("没有买卖就没有伤害");
        operateIntergralVo.setPk(orderInfo.getOrderNo());
        operateIntergralVo.setUserId(orderInfo.getUserId());
        operateIntergralVo.setValue(orderInfo.getIntergral());
       Result result= payIntergralFeignApi.inseIntergral(operateIntergralVo);
       if(result==null||result.hasError()){
               throw new BusinessException(SeckillCodeMsg.INTERGRAL_ERROR);
           }


        //修改状态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);

       if(count==0){
            throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
        }
       //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillId(),orderInfo.getSeckillTime());
        //修改本地标识
        rocketMQTemplate.syncSend(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
        }
}